package org.example.fronted.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.text.RandomStringGenerator;
import org.example.entity.Data;
import org.example.entity.Goods;
import org.example.entity.Orders;
import org.example.entity.WebOrders;
import org.example.fronted.mapper.CartMapper2;
import org.example.fronted.mapper.GoodMapper;
import org.example.fronted.mapper.OrderMapper;
import org.example.fronted.mapper.UserMapper2;
import org.example.fronted.service.OrderService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Transactional
public class OrderServiceImpl implements OrderService {

    @Value("${imageServer}")
    private String imageServerLocation;

    @Resource
    private GoodMapper goodMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private CartMapper2 cartMapper2;
    @Resource
    private UserMapper2 userMapper2;

//    public OrderServiceImpl(UserMapper2 userMapper2) {
//        this.userMapper2=userMapper2;
//    }


    @Override
    public Data ensureOrder(Map<Integer, Integer> goodsInfo, Integer defaultTakeDeliveryAddressId, Integer userId) {
        /**
         * 1. 首先要判断库存是否充足，更新库存。
         * 2. 如果库存充足的情况下，生成订单。
         * 3. 插入用户的订单和收货地址
         * 4. 删除购物车数据。
         */
        Set<Integer> goodIds = goodsInfo.keySet(); // 获取所有的商品的id
        String oderNo = null;

        // 将Set集合转换为list集合
        List ids = new ArrayList(goodIds);

        // 将集合转换一个对应类型的数组
        // Integer[] ids = goodIds.toArray(new Integer[goodIds.size()]);

        // 因为订单表中得插入 商品几乎所有的信息
        // List<Goods> goodList = goodMapper.selectBatchIds(ids);
        QueryWrapper<Goods> wrapper = new QueryWrapper<>();
        List<Goods> goodList = goodMapper.selectList(wrapper.in("goods_id", ids));

        Data data = new Data() ;

        //总的价格， 要在前端支付的价格
        BigDecimal totalPrice = BigDecimal.valueOf(0);

        // 需要返回到前端的数据
        Map<String, Object> resultData = new HashMap<>();

        for (Integer goodId : goodIds) {
            // 对不同进行上锁
            synchronized (goodId) {
                // 查询的商品的库存
                Integer stockNum = goodMapper.getStockOfSpecifiedGoods(goodId);

                // 得到用户需要购买的数量
                Integer realBuyNum = goodsInfo.get(goodId);

                // 用户要购买的数量大于实际的库存
                if (realBuyNum > stockNum) {
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    data = new Data(-1, "库存不够.");
                    return data;
                    // throw new RuntimeException("库存不够");
                } else {  //库存够用户购买
                    // 如果够的话，就更新库存
                    goodMapper.updateStockNum(stockNum - realBuyNum, goodId);
                }
            }
        }

        oderNo = generateOrderNo(); //获取订单编号
        System.out.println(oderNo);
        resultData.put("orderNo", oderNo);

        for (Goods g : goodList) {
            Integer goodId = g.getGoodsId();
            BigDecimal price = g.getPrice(); //商品的价格
            String title = g.getTitle();
            String image = g.getSmallPic();
            Integer num = goodsInfo.get(goodId); //实际购买的商品的数量

            Date creatTime = new Date();
            // 插入订单
            Integer row = orderMapper.insertOrder(oderNo, g.getPrice(), num, image, title, 0, 0, userId, creatTime, goodId);

            System.out.println("插入条数：" + row);


            /**
             * add()   加上
             * multiply()  乘法
             * divide()   除法
             * subtract() 减法
             */
            totalPrice = totalPrice.add(price.multiply(BigDecimal.valueOf(num)));
        }

        // 插入订单的收货地址
        orderMapper.insertOrderAddress(oderNo, defaultTakeDeliveryAddressId);

        // 删除用户的购物车数据
        cartMapper2.deleteShoppingCartDataOfUser(userId);

        data = new Data(1, "成功");

        resultData.put("totalPrice", totalPrice);

        data.setObj(resultData);  //设置总的价格

        return data;
    }

    @Override
    public Data confirmPay(String orderNo, Integer userId) {
        /**
         * 确认支付的流程：
         *      1.扣除金额(但是要先判断金额是否够)
         *      2.修改订单的状态，变为 “已支付”
         */
        BigDecimal balance = userMapper2.getBalanceOfUser(userId); //获取用户的余额

        // 查询对应订单编号的所有的订单，目的是为了计算订单的总金额
        List<Orders> list = orderMapper.getOrdersOfOrderNo(orderNo);

        // 需要支付的总金额
        BigDecimal totalPrice = BigDecimal.valueOf(0);

        // 集合有流处理
        for(Orders o : list) {
            BigDecimal price = o.getOGoodPrice(); //获取商品的价格
            Integer num = o.getONum(); //获取商品的数量


            // 单个商品的总价格
            BigDecimal singleGoodsTotalPrice = price.multiply(new BigDecimal(num));

            System.out.println(singleGoodsTotalPrice);

            totalPrice = totalPrice.add(singleGoodsTotalPrice);
        }

        Data data = new Data();

        BigDecimal remainBalance = null;
        /**
         * balance如果小于totalPrice，返回 -1
         * balance如果等于totalPrice，返回 0
         * balance如果大于totalPrice，返回 1
         */
        if(balance.compareTo(totalPrice) >= 0) {  // 用户的余额足够支付订单
            remainBalance = balance.subtract(totalPrice);
        }else {  //钱不够
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            data = new Data(-1, "你的余额不足.");
            return data;
        }

        try {
            userMapper2.updateBalanceOfUser(remainBalance, userId);  //更新用户的余额

            Date date = new Date();

            // 更新订单的状态，变为已支付
            orderMapper.updateOrdersStatus(orderNo, 1, date);

        }catch (Exception ex) {
            data = new Data(-2, "支付失败, 请稍后再试.");
            return data;
        }

        data = new Data(1, "支付成功");
        return data;
    }

    @Override
    public List<WebOrders> getOrdersByStatus(Integer status, Integer userId) {
        List<Orders> ordersList = orderMapper.getOrdersByStatus(status, userId);

        List<WebOrders> webOrderList = new ArrayList<>();

        /**
         * map作用是将订单按照订单编号来分类。key是订单编号，value是拥有相同订单编号的订单.
         */
        Map<String, List<Orders>> map = new HashMap<>();

        /**
         * map的作用是存储对应订单的创建日期，key是订单编号，value是订单的创建日期
         */
        Map<String, Date> orderTimeMap = new HashMap<>();

        for(Orders o : ordersList) {
            String oNo = o.getONo(); //订单编号
            Date createTime = o.getOCreateTime(); //订单的创建日期
            o.setOGoodImg(imageServerLocation + o.getOGoodImg());

            // 获取该订单编号的创建日期
            Date createDate = orderTimeMap.get(oNo);
            if(null == createDate) {
                orderTimeMap.put(oNo, createTime);
            }

            /**
             * [
             *    {orderNo: 1, XXXXX},  map -> {1: list[xxxxx]}
             *    {orderNo: 1, ZZZZ},  map -> {1: list[xxxxx, ZZZZ]}
             *    {orderNo: 2, yyyyy}, map ->{1: list[xxxxx, ZZZZ], 2: list[yyyyy]}
             *    {orderNo: 2, oooo},  map ->{1: list[xxxxx, ZZZZ], 2: list[yyyyy]}
             *    {orderNo: 2, XXXXX},
             * ]
             */
            // 获取该订单编号对应的所有的订单
            List<Orders> orders = map.get(oNo);
            if(null == orders) {  //该订单编号没有对应的订单
                orders = new ArrayList<>();
                orders.add(o);
                map.put(oNo, orders);
            }else { //该订单编号有订单了
                orders.add(o);
            }
        }


        map.forEach((k, v) -> {
            WebOrders webOrder = new WebOrders();

            webOrder.setOrderNo(k);
            webOrder.setOrders(v);

            Date createTime = orderTimeMap.get(k);  //订单的创建日期

            webOrder.setCreateTime(createTime);

            webOrderList.add(webOrder);
        });

        return webOrderList;
    }

    @Override
    public String generateOrderNo() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

        String datePrefix = sdf.format(date);

        RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange(new char[]{'0', '9'}).build();

        String randomNum = generator.generate(6);

        return datePrefix + randomNum;
    }
}
